#include "stdafx.h"
#include "VertexBuffer.h"
#include "VertexFormats.h"
#include "GraphicsManager.h"
#include <assert.h>

using namespace VertexFormats;

VertexBuffer::VertexBuffer(void* vertex_buffer, unsigned int* index_buffer, unsigned int vertexCount, unsigned int indexCount, Vertex_Type type, bool dynamic)
{
	this->vertex_count = vertexCount;
	this->index_count = indexCount;
	this->dynamic = dynamic;

	D3D11_BUFFER_DESC vbuffer_desc;
	ZeroMemory(&vbuffer_desc, sizeof(D3D11_BUFFER_DESC));

	struct_size = vertex_stride = 0;
	switch (type)
	{
	case VERTEX_TYPE_POSITION:
		struct_size = sizeof(Vertex);
		inputLayout = Vertex::getInputLayout();
		break;
	case VERTEX_TYPE_POSITION_TEXCOORD:
		struct_size = sizeof(VertexTexture);
		inputLayout = VertexTexture::getInputLayout();
		break;
	case VERTEX_TYPE_POSITION_COLOR:
		struct_size = sizeof(VertexColor);
		inputLayout = VertexColor::getInputLayout();
		break;
	case VERTEX_TYPE_POSITION_TEXCOORD_NORMAL:
		struct_size = sizeof(VertexNormalTexture);
		inputLayout = VertexNormalTexture::getInputLayout();
		break;
	case VERTEX_TYPE_POSITION_TEXCOORD_NORMAL_TANGENT:
		struct_size = sizeof(VertexNormalTextureTangent);
		inputLayout = VertexNormalTextureTangent::getInputLayout();
		break;
	}

	vertex_stride = struct_size;

	assert(inputLayout && "Failed to build input layout!");

	vbuffer_desc.ByteWidth = struct_size * vertexCount;
	vbuffer_desc.Usage = dynamic ? D3D11_USAGE_DYNAMIC : D3D11_USAGE_DEFAULT ;
	vbuffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	if (dynamic)
		vbuffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

	D3D11_SUBRESOURCE_DATA subresource_data;
	ZeroMemory(&subresource_data, sizeof(D3D11_SUBRESOURCE_DATA));
	subresource_data.pSysMem = vertex_buffer;

	vertexData = new char[struct_size * vertexCount];
	memcpy(vertexData, vertex_buffer, struct_size * vertexCount);

	GraphicsManager::GetInstance()->MakeBuffer(&vertexBuffer, &vbuffer_desc, vertex_buffer);

	D3D11_BUFFER_DESC indexBuffer_desc;
	ZeroMemory(&indexBuffer_desc, sizeof(D3D11_BUFFER_DESC));

	indexBuffer_desc.ByteWidth = indexCount * sizeof(int);
	indexBuffer_desc.Usage = D3D11_USAGE_DEFAULT;
	indexBuffer_desc.BindFlags = D3D11_BIND_INDEX_BUFFER;

	D3D11_SUBRESOURCE_DATA indexSubresources_data;
	ZeroMemory(&indexSubresources_data, sizeof(D3D11_SUBRESOURCE_DATA));

	indexSubresources_data.pSysMem = indexBuffer;

	indexData = new unsigned int[indexCount];
	memcpy(indexData, index_buffer, indexCount * sizeof(unsigned int));

	GraphicsManager::GetInstance()->MakeBuffer(&indexBuffer, &indexBuffer_desc, index_buffer);
}

VertexBuffer::~VertexBuffer(void)
{
	if (inputLayout)
		inputLayout->Release();
	if (vertexBuffer)
		vertexBuffer->Release();
	if (indexBuffer)
		indexBuffer->Release();
	delete[] vertexData;
	delete[] indexData;
}


void VertexBuffer::setData(void* vertexBuffer, unsigned int pixelStride)
{
	assert(dynamic && "Vertex buffer must be dynamic to setData!");

	// store a pointer to graphics
	GraphicsManager* pGraphics = GraphicsManager::GetInstance();

	D3D11_MAPPED_SUBRESOURCE subresource;
	ZeroMemory(&subresource, sizeof(D3D11_MAPPED_SUBRESOURCE));
	
	// update buffer in graphics memory
	pGraphics->getDeviceContext()->Map((ID3D11Resource*)this->vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &subresource);
	memcpy(subresource.pData, vertexBuffer, vertex_count * pixelStride);
	pGraphics->getDeviceContext()->Unmap(this->vertexBuffer, 0);

	memcpy(vertexData, vertexBuffer, vertex_count * pixelStride);
}
/*virtual*/ void VertexBuffer::getData(void* data, unsigned int pixelStride) /*override*/
{
	memcpy(data, vertexData, struct_size * vertex_count);
}

void VertexBuffer::getIndexData(unsigned int** data)
{
	*data = new unsigned int[index_count];
	memcpy(*data, indexData, index_count * sizeof(unsigned int));
}